//////////////////////////////////////////////
// main.cpp
//
//////////////////////////////////////////////

/// Includes ---------------------------------

// nkLog
#include <NilkinsLog/Loggers/ConsoleLogger.h>

// nkGraphics
#include <NilkinsScripts/Log/LogManager.h>

#include <NilkinsScripts/Environments/Functions/Function.h>

#include <NilkinsScripts/Environments/Environment.h>
#include <NilkinsScripts/Environments/EnvironmentManager.h>

#include <NilkinsScripts/Interpreters/Interpreter.h>

#include <NilkinsScripts/Scripts/Script.h>
#include <NilkinsScripts/Scripts/ScriptManager.h>

// Standards
#include <memory>

/// Callback ---------------------------------

// Simple callback returning a constant
nkScripts::OutputValue customCallback (const nkScripts::DataStack& stack)
{
	return nkScripts::OutputValue(5) ;
}

// Callback interpreting parameters
nkScripts::OutputValue customCallbackParams (const nkScripts::DataStack& stack)
{
	std::string result = stack[0]._valString + " " + stack[1]._valString ;
	return nkScripts::OutputValue(result) ;
}

/// Function ---------------------------------

int main ()
{
	// Prepare logging capabilities
	std::unique_ptr<nkLog::Logger> logger = std::make_unique<nkLog::ConsoleLogger>() ;
	nkScripts::LogManager::getInstance()->setReceiver(logger.get()) ;

	// Create the environment we will work with
	nkScripts::Environment* env = nkScripts::EnvironmentManager::getInstance()->createOrRetrieve("firstEnv") ;
	env->setEnvironmentFor(nkScripts::INTERPRETER::LUA) ;

	// Set a variable inside, which will be a string
	env->setVar("t", "Hey") ;

	// Create and execute a script to check the variable set above
	nkScripts::Script* script = nkScripts::ScriptManager::getInstance()->createOrRetrieve("firstScript") ;
	script->setTargetInterpreter(nkScripts::INTERPRETER::LUA) ;
	script->setSources
	(
		R"eos(
			t = t .. " you" ;
		)eos"
	) ;
	script->load() ;
	env->execute(*script) ;

	// Getting a variable is done through its name, and overload is chosen based on the default value to return if it is not found
	// As such, here we are requesting it as a a string, which will be empty if non existing
	std::string t = env->getVar("t", "") ;

	logger->log(t, "main") ;

	// Let's try setting a function in the environment now
	// We declare it on the environment and specify which C++ function it should call
	nkScripts::Function* func = env->setFunc("customCallback") ;

	func->setFunction(customCallback) ;

	// Prepare for callback testing
	script->unload() ;
	script->setSources
	(
		R"eos(
			t = customCallback() ;

			print(t) ;
		)eos"
	) ;
	script->load() ;
	env->execute(*script) ;

	// Prepare for augmented callback to have something more crunchy
	func->setFunction(customCallbackParams) ;

	// This time the function will need 2 string parameters
	// They need to be declared upfront for the component to know what to do
	func->addParameter(nkScripts::FUNCTION_PARAMETER_TYPE::STRING) ;
	func->addParameter(nkScripts::FUNCTION_PARAMETER_TYPE::STRING) ;

	// Prepare script for new execution to check addition
	script->unload() ;
	script->setSources
	(
		R"eos(
			t = customCallback("nkScripts", "rocks") ;

			print(t) ;
		)eos"
	) ;
	script->load() ;
	env->execute(*script) ;

	// Small pause to be able to witness the console
	system("pause") ;

	return 0 ;
}